package com.eva.admin.biz.system.dict;

import com.eva.admin.dao.system.dict.SystemDictMapper;
import com.eva.admin.biz.system.dict.dto.CreateSystemDictDTO;
import com.eva.admin.biz.system.dict.dto.UpdateSystemDictDTO;
import com.eva.admin.dao.system.dict.dto.QuerySystemDictDTO;
import com.eva.dao.system.model.SystemDict;
import com.eva.dao.system.model.SystemDictData;
import com.eva.admin.dao.system.dict.vo.SystemDictVO;
import com.eva.dict.loaders.SystemDictCacheLoader;
import com.eva.framework.common.constants.ResponseStatus;
import com.eva.framework.common.exception.BusinessException;
import com.eva.framework.common.model.PageData;
import com.eva.framework.common.model.PageWrap;
import com.eva.framework.common.utils.AssertUtil;
import com.eva.framework.dict.SystemDictHelper;
import com.eva.framework.dict.model.SystemDictCache;
import com.eva.framework.dict.model.SystemDictDataCache;
import com.eva.framework.mp.utils.PageUtil;
import com.eva.service.system.SystemDictDataService;
import com.eva.service.system.SystemDictService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * 字典管理业务实现
 */
@Slf4j
@Service
public class SystemDictBiz {

    @Resource
    private SystemDictService systemDictService;

    @Resource
    private SystemDictMapper systemDictMapper;

    @Resource
    private SystemDictDataService systemDictDataService;

    @Resource
    private SystemDictCacheLoader systemDictCacheLoader;

    /**
     * 创建
     *
     * @param dto 字段信息
     * @return 主键
     */
    public Integer create(CreateSystemDictDTO dto) {
        AssertUtil.notEmpty(dto.getCode(), "字典编码不能为空");
        AssertUtil.notEmpty(dto.getName(), "字典名称不能为空");
        AssertUtil.notEmpty(dto.getScopes(), "字典作用域不能为空");
        // 验证编码是否存在
        if (systemDictService.exists(new SystemDict().setCode(dto.getCode()))) {
            throw new BusinessException(ResponseStatus.DATA_EXISTS, "字典编码已存在");
        }
        // 执行创建
        SystemDict newDict = new SystemDict();
        BeanUtils.copyProperties(dto, newDict);
        Integer id = systemDictService.create(newDict);
        // v5.1.0，重新加载至缓存
        this.reloadToCache();
        return id;
    }

    /**
     * 根据ID删除
     *
     * @param id ID
     */
    @Transactional
    public void deleteById (Integer id) {
        // v5.1.0，整体调整
        this.deleteById(id, Boolean.TRUE);
    }

    /**
     * 根据ID集批量删除
     *
     * @param ids ID集
     */
    @Transactional
    public void deleteByIdInBatch (List<Integer> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return;
        }
        for (Integer id : ids) {
            // v5.1.0，单个删除不重新加载至缓存
            this.deleteById(id, Boolean.FALSE);
        }
        // v5.1.0，重新加载至缓存
        this.reloadToCache();
    }

    /**
     * 根据主键修改
     *
     * @param dto 更新后的字段信息
     */
    public void updateById(UpdateSystemDictDTO dto) {
        AssertUtil.notEmpty(dto.getId(), "主键不能为空");
        AssertUtil.notEmpty(dto.getCode(), "字典编码不能为空");
        AssertUtil.notEmpty(dto.getName(), "字典名称不能为空");
        AssertUtil.notEmpty(dto.getScopes(), "字典作用域不能为空");
        AssertUtil.notEmpty(systemDictService.findById(dto.getId()), ResponseStatus.DATA_EMPTY);
        // 验证编码是否存在
        SystemDict dict = SystemDict.builder().id(dto.getId()).code(dto.getCode()).build();
        if (systemDictService.exists(dict)) {
            throw new BusinessException(ResponseStatus.DATA_EXISTS, "字典编码已存在");
        }
        // 执行修改
        SystemDict newDict = new SystemDict();
        BeanUtils.copyProperties(dto, newDict);
        systemDictService.updateById(newDict);
        // v5.1.0，重新加载至缓存
        this.reloadToCache();
    }

    /**
     * 分页查询
     *
     * @param pageWrap 分页参数
     * @return 分页数据
     */
    public PageData<SystemDictVO> findPage(PageWrap<QuerySystemDictDTO> pageWrap) {
        PageHelper.startPage(pageWrap.getPage(), pageWrap.getCapacity());
        List<SystemDictVO> dictList = systemDictMapper.search(pageWrap.getModel(), pageWrap.getOrderByClause());
        return PageUtil.from(new PageInfo<>(dictList));
    }

    /**
     * 根据ID删除
     * v5.1.0新增
     *
     * @param id ID
     * @param reloadToCache 是否重新加载至缓存
     */
    private void deleteById (Integer id, Boolean reloadToCache) {
        // 删除字典
        systemDictService.deleteById(id);
        // 查询字典数据
        SystemDictData queryDataDto = new SystemDictData();
        queryDataDto.setDictId(id);
        Set<Integer> dataIds = systemDictDataService.findIds(queryDataDto);
        systemDictDataService.deleteByIdInBatch(dataIds, Boolean.FALSE);
        // 重新加载至缓存
        if (reloadToCache) {
            this.reloadToCache();
        }
    }

    /**
     * 重新加载至缓存
     * v5.1.0 新增，实现数据字典操作后自动刷新缓存
     */
    private void reloadToCache () {
        // 获取到全部数据作用域
        SystemDictCache dictCache = SystemDictHelper.build().getDict("DATA_SCOPES");
        // 重新强制加载所有数据作用域下的字典数据
        for (SystemDictDataCache dataCache : dictCache.getDataList()) {
            systemDictCacheLoader.loadToCache(dataCache.getValue(), Boolean.TRUE);
        }
    }
}
